/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "StdAfx.h"

//#define MINION_EXPORTS

#include "WindowChecker.h"
#include "Minion_External.h"
#include ".\classwindow.h"
#include "SSI_StdFuncsExport.h"
#include "PhantomBase.h"
#include "SSI_StdFuncsExport.h"
#include "MemoryMapper.h"
#include "Phantom_InternalErrors.h"

#include <windows.h>


CDataWindow::CDataWindow(void)
{
	  if(!sType){
			sType = 1;
			sType = Factory_RegisterData((CData*)new CDataWindow());
		}
		Type = sType;
		DataName = "window";
		iWinTag = 0;
		Path = 0;
    myWin = 0;
    setWin = 0;
}

CDataWindow::~CDataWindow(void)
{
	if(Path){
		DelDataNodeTree(Path);
		Path = 0;
	}
}

SSI_BOOL CDataWindow::CopyData(CData* Other)
{
	CDataWindow* aWin = (CDataWindow*)Other;
	WinClass = aWin->WinClass;
	WinTag = aWin->WinTag;
	WinName = aWin->WinName;
	WinType = aWin->WinType;

	iWinTag = aWin->iWinTag;
	Path = CopyPath(aWin->Path);

	LocVarSet = aWin->LocVarSet;
  setWin = aWin->setWin;
	return 1;
}

CData* CDataWindow::MakeData(void)
{
	return (CData*) new CDataWindow();
}

SSI_BOOL CDataWindow::DeleteData(CData* In)
{
	delete ((CDataWindow*)In);
	return 1;
}

SSI_BOOL CDataWindow::DataFromString(const String& sData)
{
	return 0;
}

String CDataWindow::GetString(void)
{
	String Ret;
  if(setWin){
    Ret.Format("Handle: %d", setWin);
  }else if(iWinTag){
    Ret.Format("Tag: %d Class: '%s'", iWinTag, WinClass.Str());
	}else{
		Ret.Format("Tag: '%s' Class: '%s'", WinTag.Str(), WinClass.Str());
	}
	return Ret;
}

SSI_INT64 CDataWindow::SizeOf(void)
{
	return 0;
}

CData* CDataWindow::operator_equal(CData* InData, OpInfoT* Info)
{
	if(InData->GetType() != Type){
		return SSI_NULL;
	}
	CopyData(InData);
	return (CData*)this;
}


//CStatus CDataWindow::EvalClass(VarItor InVars, VarTree& InTree, CStatement& aStat)
//{
	// THIS FUNCTION IS DEPRECATED

	/*
	CStatus Ret;
	//InVar here dont matter!
	if((aStat.Type == S_EVALUATE) || (aStat.Type == S_GETVAR)){
		String name;
		if(aStat.Type == S_GETVAR){
			name = aStat.RetVar.Name;
		}else{
			name = aStat.Line;
		}
	}else if(aStat.Type == S_FUNCTION){
		return STAT_ERR;
		/*
		String name;

		/// NOTE THAT 'theFunction' also contains the parameter list!
		name = aStat.aFunction.Name;
		if(name == "GetText"){
			CDataString aVal;
			Ret = GetText(aVal.Data);
			if(!Ret){
				return Ret;
			}
			aStat.RetVar.SetType(CDataString::GetRegisteredType());
			aStat.RetVar.SetData(&aVal);
			return STAT_OK;
		}
		if(name == "SetText"){
			CDataString aVal;

			if(aStat.aFunction.GetNumParams() != 1){
				return CStatus(sERROR, "SetText requires 1 string parameter");
			}

			// OK need a method of checking function prototypes
		
			// Since many data types can have functions, should have
			//  a register function, and a function processor.  So,
			//  we can use the same function in the Engine that
			//  accepts registered functions (and same structure),
			//  This will allow for common function processing, and
			//  will be a part of the standard CData... Check that
			//  it doesnt interfere with CDataClass, and see if
			//  CDataClass can benefit from it...
			// Perhaps make a FunctionRegistrar class that can be
			//  used by both CData and CEngine?

			// USE THE EXISTING CFUNCTIONSET CLASS
			//  SEE HOW CENGINE USES IT IN DOFUNCTION,
			//  ADDFUNCTION, AND GETFUNCTIONDECL

			aVal = (CDataString&)aStat.aFunction.GetVariable(0).GetWorkingData();

			Ret = SetText(aVal.Data);
			if(!Ret){
				return Ret;
			}
			//aStat.RetVar.SetType(CDataString::GetRegisteredType());
			//aStat.RetVar.SetData(&aVal);
			
			
		}
		
	}else if(aStat.Type == S_OPERATOR){
		if(aStat.anOperator.Type == oEQUAL){
			if(aStat.anOperator.Right_Var.GetType() != CDataString::GetRegisteredType()){
				return STAT_ERR;
			}
			if(aStat.anOperator.Left_Var.Name == "Tag"){
				CDataString& aData = (CDataString&)aStat.anOperator.Right_Var.GetWorkingData();
				WinTag = aData.Data;
				return STAT_OK;
			}
			if(aStat.anOperator.Left_Var.Name == "Class"){
				CDataString& aData = (CDataString&)aStat.anOperator.Right_Var.GetWorkingData();
				WinClass = aData.Data;
				return STAT_OK;
			}

	  }
	}
	*/
//	return STAT_ERR;  // Internal Error... Deprecated
//}



HWND CDataWindow::FindPartialWindow(HWND Par, HWND Child, String& Class, String& Tag, BOOL PartClass, BOOL PartTag)
{
		CWnd* Parent = new CWnd();
		char sTemp[1024];
		CString ClassText; 
		CString WinText;

		CString TempTag = Tag.Str();
		CString TempClass = Class.Str();

		HWND hWin = Child;

		while((hWin = FindWindowEx(Par, hWin, SSI_NULL, SSI_NULL))){
			if(IsWindow(hWin)){
				if(Parent->m_hWnd){
					Parent->Detach();
				}

				if(Parent->FromHandlePermanent(hWin) != SSI_NULL){
					Parent->Detach();
					delete Parent;
					return SSI_NULL;
				}
				GetClassName(hWin, sTemp, 1024);
				Parent->Attach(hWin);
				ClassText.Format("%s", sTemp);
				Parent->GetWindowText(WinText);
				if((ClassText == "") && (WinText == "")){
				}else if((ClassText == "") && (TempClass == "")){
					if(WinText.Find(Tag) >=0){
						Parent->Detach();
						delete Parent;
						return hWin;
					}
				}else if((WinText == "") && (TempTag == "")){
					if(ClassText.Find(Class) >=0){
						Parent->Detach();
						delete Parent;
						return hWin;
					}
				}else{
					if(PartClass && PartTag){
						if((WinText != "") && (ClassText != "")){
							if(((ClassText.Find(Class) >=0) || TempClass == "") && ((WinText.Find(Tag) >=0) || TempTag == "")){
								Parent->Detach();
								delete Parent;
								return hWin;
							}
						}
					}else if(PartClass){
						if(ClassText != ""){
							if((ClassText.Find(Class) >= 0) && ((WinText == Tag) || (TempTag==""))){ // Need this in case partial class and numeric tag
								Parent->Detach();
								delete Parent;
								return hWin;
							}
						}
					}else if(PartTag){
						if(WinText != ""){
							if((WinText.Find(Tag) >= 0) && (ClassText == Class)){
								Parent->Detach();
								delete Parent;
								return hWin;
							}
						}
					}
				}
			}else{
				delete Parent;
				return SSI_NULL;
			}
			Parent->Detach();
		}
		delete Parent;
		return SSI_NULL;
}


HWND CDataWindow::FindNumericWindow(HWND Par, String& inClass, SSI_INT64 iTag, BOOL PartClass)
{
	int ctr;
	HWND hWin = SSI_NULL;

	if((iTag > 255) || (iTag < 1)){
		// ***************  Try without class
		if(PartClass){
			hWin = FindPartialWindow(Par, SSI_NULL, inClass, String("")/*SSI_NULL*/, PartClass, FALSE);
		}else{
			hWin = FindWindowEx(Par, SSI_NULL, inClass.Str(), SSI_NULL);
		}
		if(IsWindow(hWin)){
				return hWin;
		}		
		return SSI_NULL;		
	}
	for(ctr = 1; ctr <= iTag; ctr++){
		if(PartClass){
			hWin = FindPartialWindow(Par, hWin, inClass, String("")/*SSI_NULL*/, PartClass, FALSE);
		}else{
			hWin = FindWindowEx(Par, hWin, inClass.Str(), SSI_NULL);
		}

		if(!IsWindow(hWin)){
			return SSI_NULL;
		}
	}
	return hWin;
}

CStatus CDataWindow::FindMe(UINT& Val, HMENU& hMenu)
{
	CStatus Ret;
	String Class;
	String Tag;
  String Name;
	String Star = "*";
	int Pos;

	BOOL TagStar = 0;
	BOOL ClassStar = 0;

	HWND Par = 0;
	myWin = 0;

	DataNode aNode = Path;
	while(aNode){
		Class = *aNode->WinClass;
		Tag = *aNode->WinTag;
    Name = *aNode->WinName;

		if((Class == "MenuItem") || (Class == "Menu")){
			myWin = (HWND)FindMenu(Par, aNode, Val, hMenu);
      if(myWin){
			  return STAT_OK;
      }else{
        //return STAT_ERR; // This may be just to send a FALSE so dont override
        MAKEERR3(ERR_P00100, Name.Str(), Class.Str(), Tag.Str());
      }
		}

		Pos = Tag.FindOneOf(Star);
		if(Pos >= 0){
			TagStar = TRUE;
			Tag = Tag.Left(Pos);
		}

		Pos = Class.FindOneOf(Star);
		if(Pos >= 0){
			ClassStar = TRUE;
			Class = Class.Left(Pos);
		}

		if(aNode->iWinTag > 0){
			Par = FindNumericWindow(Par, Class, aNode->iWinTag, ClassStar);
		  if(!Par){
			  //return STAT_ERR;  // This is just to send an FALSE, so dont override
        MAKEERR3(ERR_P00104, Name.Str(), Class.Str(), aNode->iWinTag);
		  }

		}else if(ClassStar || TagStar){
			Par = FindPartialWindow(Par, SSI_NULL, Class, Tag, ClassStar, TagStar);
		}else{
			Par = FindWindowEx(Par, SSI_NULL, aNode->WinClass->Str(), aNode->WinTag->Str());
		}

		if(!Par){
			//return STAT_ERR;  // This is just to send an FALSE, so dont override
      MAKEERR3(ERR_P00100, Name.Str(), Class.Str(), Tag.Str());
		}
		aNode = aNode->FChild;
	}

	Class = WinClass;
	Tag = WinTag;

	Pos = Tag.FindOneOf(Star);
	if(Pos >= 0){
		TagStar = TRUE;
		Tag = Tag.Left(Pos);
	}
	Pos = Class.FindOneOf(Star);
	if(Pos >= 0){
		ClassStar = TRUE;
		Class = Class.Left(Pos);
	}


  // Top-level menu fix, but need aNode's parent (it will be NULL here)
  //if(((Class == "MenuItem") || (Class == "Menu")) && aNode->Parent){
  //  myWin = (HWND)FindMenu(Par, aNode->Parent, Val, hMenu);
  //  if(myWin){
	//	  return STAT_OK;
  //  }else{
  //    return STAT_ERR;
  //  }
	//}
  if((Class == "MenuItem") || (Class == "Menu")){
		myWin = (HWND)FindMenu(Par, aNode, Val, hMenu);
    if(myWin){
      return STAT_OK;
    }else{
      //return STAT_ERR; // This may be just to send a FALSE so dont override
      MAKEERR3(ERR_P00100, Name.Str(), Class.Str(), Tag.Str());
    }
	}

	if(iWinTag > 0){
		myWin = FindNumericWindow(Par, Class, iWinTag, ClassStar);
	}else if(ClassStar || TagStar){
		myWin = FindPartialWindow(Par, SSI_NULL, Class, Tag, ClassStar, TagStar);
	}else{
		myWin = FindWindowEx(Par, SSI_NULL, WinClass.Str(), WinTag.Str());
	}

	if(!myWin){
    MAKEERR3(ERR_P00100, Name.Str(), Class.Str(), Tag.Str());
	}
	return STAT_OK;
}

CStatus CDataWindow::GetText(String& Ret)
{
	/*
	HWND hWin;
	CStatus RetStat;
	RetStat = FindMe(hWin);
	if(!RetStat) return RetStat;

	CWnd* Win = new CWnd;

	char Params[SHRT_MAX];  //Because needs to know the size, for some reason

	Win->Attach(hWin);
	Win->SendMessage(WM_GETTEXT, SHRT_MAX, (LPARAM)&Params);
	Ret.Format("%s", &Params[0]);
	Win->Detach();
	delete Win;

	return STAT_OK;
	*/
	// Deprecated
	return STAT_ERR; // Internal Error, Deprecated
}

CStatus CDataWindow::SetText(String& Set)
{
	/*
	HWND hWin;
	CStatus RetStat;
	RetStat = FindMe(hWin);
	if(!RetStat) return RetStat;

	CWnd* Win = new CWnd;

	Win->Attach(hWin);
	Win->SendMessage(WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Set.Str());
	Win->Detach();

	delete Win;

	return STAT_OK;
	*/
	// deprecated
	return STAT_ERR; // Internal Error, Deprecated
}

CStatus CDataWindow::InitData(void)
{
	MinionClear();

	CFunctionDecl aNewFunc;
	String Class;
  // MainWin Functions
	Class = "MainWin";

	aNewFunc.Name = "AddChild";
  aNewFunc.addType(CDataWindow::GetRegisteredType());
  aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetPath";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);
	
	aNewFunc.Clear();
	aNewFunc.Name = "GetText";
  aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "SetText";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Maximize";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Minimize";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Restore";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Close";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "KeyDown";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "KeyUp";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "BringToTop";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "SetActive";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "MoveWin";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "MouseMove";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "MouseClick";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "TypeKeys";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "ResizeWin";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "MainWin";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = Type;
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "MainWin";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = Type;
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Menu";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = Type;
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "MenuItem";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = Type;
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);


	aNewFunc.Clear();
	aNewFunc.Name = "GetHandle";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "SetHandle";
  aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetWindowX";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetWindowY";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetWindowWidth";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetWindowHeight";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsActive";
  aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Blink";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetCaretX";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetCaretY";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);


	aNewFunc.Clear();
	aNewFunc.Name = "CaptureBitmap";
	aNewFunc.ReturnType = CDataBitmap::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsEnabled";   // Window IsEnabled, not Menu
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetChild";
	aNewFunc.ReturnType = CDataWindow::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetParent";
	aNewFunc.ReturnType = CDataWindow::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetNextSibling";
	aNewFunc.ReturnType = CDataWindow::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetPrevSibling";
	aNewFunc.ReturnType = CDataWindow::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetTopParent";
	aNewFunc.ReturnType = CDataWindow::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);



	// Tab Ctrl Functions
	Class = "SysTabControl32";
	aNewFunc.Clear();
	aNewFunc.Name = "GetActiveTab";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetTabText";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "SelectTab";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);
	
	aNewFunc.Clear();
	aNewFunc.Name = "GetCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);


	// Button Functions
	Class = "Button";
	aNewFunc.Clear();
	aNewFunc.Name = "Click";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsSelected";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsChecked";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// ScrollBar Functions
	Class = "ScrollBar";
	aNewFunc.Clear();
	aNewFunc.Name = "SetPos";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetPos";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetMaximum";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetMinimum";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// TreeView Functions
	Class = "SysTreeView32";
	aNewFunc.Clear();
	aNewFunc.Name = "GetCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetSelected";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Select";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Expand";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Collapse";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsExpanded";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// ListView Functions
	Class = "SysListView32";

	aNewFunc.Clear();
	aNewFunc.Name = "GetCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetColumnCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);
  
  aNewFunc.Clear();
	aNewFunc.Name = "GetItemText";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
  aNewFunc.addType(CDataInt::GetRegisteredType());
  aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

  aNewFunc.Clear();
	aNewFunc.Name = "GetColumnText";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
  aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Select";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);


  //aNewFunc.Clear();
	//aNewFunc.Name = "GetItemBounds";
	//aNewFunc.ReturnType = CDataInt::GetRegisteredType();
  //aNewFunc.addType(CDataInt::GetRegisteredType());
	//aNewFunc.SetProcessor(this);
	//AddFunction(aNewFunc, Class);



  // ComboBox Functions
	Class = "ComboBox";

	aNewFunc.Clear();
	aNewFunc.Name = "GetCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Select";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetElement";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// ListBox Functions
	Class = "ListBox";

	aNewFunc.Clear();
	aNewFunc.Name = "GetCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetElement";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Select";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "SelectString";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetSel";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// ToolBar Functions
	Class = "ToolbarWindow32";

	aNewFunc.Clear();
	aNewFunc.Name = "GetCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "GetRows";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "PressButton";
	aNewFunc.addType(CDataInt::GetRegisteredType());
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// HTMLView Functions
	Class = "Internet Explorer_Server";
	aNewFunc.Clear();
	aNewFunc.Name = "LoadURL";
	aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	// JVM Functions
	Class = "jvm";
	aNewFunc.Clear();
	aNewFunc.Name = "GetJVM";
	//aNewFunc.addType(CDataString::GetRegisteredType());
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);



	// Menu Functions
	Class = "MenuItem";

	aNewFunc.Clear();
	aNewFunc.Name = "IsChecked";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Select";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsEnabled";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsSeparator";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

  aNewFunc.Clear();
	aNewFunc.Name = "GetMenuText";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

  aNewFunc.Clear();
	aNewFunc.Name = "GetMenuCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);
  
  Class = "Menu";

	aNewFunc.Clear();
	aNewFunc.Name = "IsChecked";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "Select";
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsEnabled";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

	aNewFunc.Clear();
	aNewFunc.Name = "IsSeparator";
	aNewFunc.ReturnType = CDataBool::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

  aNewFunc.Clear();
	aNewFunc.Name = "GetMenuText";
	aNewFunc.ReturnType = CDataString::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);

  aNewFunc.Clear();
	aNewFunc.Name = "GetMenuCount";
	aNewFunc.ReturnType = CDataInt::GetRegisteredType();
	aNewFunc.SetProcessor(this);
	AddFunction(aNewFunc, Class);


////
	CVariable aVar;
	aVar.Name = "Tag";
	aVar.SetType(CDataString::GetRegisteredType());
	AddVariable(aVar);

	aVar.Name = "Class";
	aVar.SetType(CDataString::GetRegisteredType());
	AddVariable(aVar);


	return STAT_OK;
}

void CDataWindow::SSI_FunctionProcessor(SSI_FunctionAPI& theAPI)
{
	CStatus RetStat;
	String LocClass;
	CMemoryMapper aMap;
	char* aptr = 0;

  if(theAPI.m_FunctionName == "AddChild"){
    CDataWindow Child;
    
    // Must use operator_equal, else pointer will be copied
    Child.operator_equal((CDataWindow*)theAPI.GetSingleData(0), 0);
    Child.setWin = 0;
    CDataString Name = *(CDataString*)theAPI.GetSingleData(1);
    Child.WinName = Name.Data;
		AddChildren(Child.CreatePathTree(), this, theAPI.m_Engine);
    return;
	}else if(theAPI.m_FunctionName == "GetPath"){
		CDataString R;
		R.Data = GetPathString();
		theAPI.SetReturnData(&R);
		return;
	}


	if(theAPI.m_FunctionName == "MainWin" || theAPI.m_FunctionName == "Menu" || theAPI.m_FunctionName == "MenuItem"){

		String sTag;
		SSI_INT64 iTag = 0;
		String sClass;

		if(theAPI.GetParameterType(0) == CDataInt::GetRegisteredType()){
			iTag = SSI_EXTRACT(CDataInt, 0);
		}else{
			sTag = SSI_EXTRACT(CDataString, 0);
		}

		sClass = SSI_EXTRACT(CDataString, 1);

		CDataWindow* aWin = (CDataWindow*)Factory_MakeData(CDataWindow::GetRegisteredType());
		if(!aWin){
			theAPI.m_ReturnStatus = STAT_ERR; // Internal Error
		}

		aWin->WinClass = sClass;
		aWin->WinName = "";
		//if(theAPI[0]->Name.GetLength() > 0){
		//	aWin->WinName = theAPI[0]->Name;  // This will use parameter 1's name if any
		//}else{
		//	aWin->WinName = "MainWin_Generic";
		//}
		
		aWin->WinTag = sTag;
		aWin->WinType = "MainWin";
		aWin->iWinTag = iTag;
		// This has to stay here so that w.MainWin(...) works.
		
		ConstructChildPath(aWin);
		RetStat = AddLocalVariable(aWin, aWin->WinName);
		if(!RetStat){
      delete aWin;
			theAPI.m_ReturnStatus = RetStat;
			return;
		}
		theAPI.m_ReturnStatus = theAPI.SetReturnData(aWin);
		delete aWin;
		return;
	}else if(theAPI.m_FunctionName == "SetHandle"){
    int H = SSI_EXTRACT(CDataInt, 0);
    if(!IsWindow((HWND)H) && H != 0){
      P_MAKEERR0(ERR_P00541);
    }else{
      setWin = (HWND)H;
	    if(Path){
		    DelDataNodeTree(Path);
		    Path = 0;
	    }
      WinClass = GetClass(setWin);
      WinTag = "";
      WinName = "";
      WinType = "";
      iWinTag = 0;
    }
    return;
  }

  // Delay
	Sleep(iDelay);

	UINT Val = 0;
	HMENU hMenu = 0;
	int FindCtr = 0;

  // Handle set via SetHandle  (maybe need separate member variable)
  if(setWin){
    if(!IsWindow(setWin)){
      P_MAKEERR1(ERR_P00542, setWin);
      return;
    }
    myWin = setWin;
    WinClass = GetClass(myWin);  // So proper functions are available
  }else{
	  // Find the window
	  while(!(RetStat = FindMe(Val, hMenu))){
		  Sleep(10);
		  FindCtr++;
		  if(FindCtr > 5*100) break;
	  }
	  if(!RetStat){
		  // RetStat above would be nothing more than a STAT_ERR
		  //P_MAKEERR3(ERR_P00100, WinName.Str(), WinClass.Str(), WinTag.Str());
		  theAPI.m_ReturnStatus = RetStat;
		  return;
	  }
  }

	// This has to be done here *after* the window is found...
	// Replace this class with defines (make sure it is not persistent)
	LocClass = Phantom_GetMappedWindow(WinClass);
	if(!(RetStat = Phantom_CheckFunction(theAPI, LocClass))){
		// This should work, because parameters must match, and it can find it as either a mainwin or class
		theAPI.m_ReturnStatus = RetStat;
		return;
	}

	// Non-minion window functions
	if(theAPI.m_FunctionName == "GetHandle"){
		CDataInt ret;
		// this goes from 64 bits to 32 bits... may not be OK?
		//ret.Data = int(myWin->unused); //reinterpret_cast<int>(hWin);
    if(setWin){
      ret.Data = int(setWin);
    }else{
      ret.Data = int(myWin);
    }
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
		return;
  }else if(theAPI.m_FunctionName == "CaptureBitmap"){
		CStatus RetStat;
		CDataBitmap ret;
		RetStat = CaptureBitmap(ret);
		if(!RetStat){
			theAPI.m_ReturnStatus = RetStat;
			return;
		}
		theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
		return;
  }else if(theAPI.m_FunctionName == "GetChild"){
		CWnd aWin;
    if(!aWin.Attach(myWin)){
      theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
    }
    CDataWindow ret;
    CWnd* Child = aWin.GetTopWindow();
    aWin.Detach();
    ret.InitializeFromWindow(Child);
    theAPI.SetReturnData(&ret);
		
		return;
  }else if(theAPI.m_FunctionName == "GetParent"){
		CWnd aWin;
    if(!aWin.Attach(myWin)){
      theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
    }
    CDataWindow ret;
    CWnd* Child = aWin.GetParent();
    aWin.Detach();
    ret.InitializeFromWindow(Child);
    theAPI.SetReturnData(&ret);
		
		return;
  }else if(theAPI.m_FunctionName == "GetNextSibling"){
		CWnd aWin;
    if(!aWin.Attach(myWin)){
      theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
    }
    CDataWindow ret;
    CWnd* Child = aWin.GetNextWindow(GW_HWNDNEXT);
    aWin.Detach();
    ret.InitializeFromWindow(Child);
    theAPI.SetReturnData(&ret);
		
		return;
  }else if(theAPI.m_FunctionName == "GetPrevSibling"){
		CWnd aWin;
    if(!aWin.Attach(myWin)){
      theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
    }
    CDataWindow ret;
    CWnd* Child = aWin.GetNextWindow(GW_HWNDPREV);
    aWin.Detach();
    ret.InitializeFromWindow(Child);
    theAPI.SetReturnData(&ret);
		
		return;
  }else if(theAPI.m_FunctionName == "GetTopParent"){
		CWnd aWin;
    if(!aWin.Attach(myWin)){
      theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
    }
    CDataWindow ret;
    CWnd* Child = aWin.GetTopLevelParent();
    aWin.Detach();
    ret.InitializeFromWindow(Child);
    theAPI.SetReturnData(&ret);
		
		return;
	// Set active cannot be in the process, because a process cannot make itself active	
  }else if(theAPI.m_FunctionName == "SetActive"){
		CWnd* aWnd = new CWnd();
		aWnd->Attach(myWin);
		CWnd* TopWin = aWnd->GetTopLevelOwner();
		if(TopWin == SSI_NULL){
			TopWin = aWnd;
		}
		HWND hWnd = TopWin->m_hWnd;
		HWND Fore = GetForegroundWindow();
		if(GetWindowThreadProcessId(hWnd, SSI_NULL) != GetWindowThreadProcessId(Fore, SSI_NULL)){
			SetForegroundWindow(hWnd);
			BringWindowToTop(hWnd);
			SetActiveWindow(hWnd);
			SetFocus(hWnd);			
		}
		aWnd->Detach();
		delete aWnd;

		theAPI.m_ReturnStatus = STAT_OK;
		return;
	}else if(theAPI.m_FunctionName == "IsEnabled"){
		if(!(Val && hMenu)){  // If not a menu
		// This is window IsEnabled
			CDataBool ret;	
			CWnd* aWnd = new CWnd();
			aWnd->Attach(myWin);
			ret.Data = aWnd->IsWindowEnabled();
			aWnd->Detach();
			delete aWnd;

			theAPI.m_ReturnStatus = theAPI.SetReturnData(&ret);
			theAPI.m_ReturnStatus = STAT_OK;
			return;
    }
	}else if(theAPI.m_FunctionName == "MouseClick"){
   	int X, Y, iType, iButton;
		iButton = SSI_EXTRACT(CDataInt, 0);
		X = SSI_EXTRACT(CDataInt, 1);
		Y = SSI_EXTRACT(CDataInt, 2);
		iType = SSI_EXTRACT(CDataInt, 3);

    CWnd* aWin = new CWnd();
	  if(!aWin){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
	  }
	  if(!aWin->Attach(myWin)){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  delete aWin;
		  return;
	  }
    MouseClick(aWin, iButton, X, Y, iType);
	  //aWin->FunctionProcessor(theAPI);
	  aWin->Detach();
	  delete aWin;
    return;
  }else if(theAPI.m_FunctionName == "TypeKeys"){
	  CWnd* aWin = new CWnd();
	  if(!aWin){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
	  }
	  if(!aWin->Attach(myWin)){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  delete aWin;
		  return;
	  }
    String s;
    s = SSI_EXTRACT(CDataString, 0);
    theAPI.m_ReturnStatus = TypeKeys(aWin, s);
	  aWin->Detach();
	  delete aWin;
    return;
	}else if(theAPI.m_FunctionName == "KeyDown"){

	  CWnd* aWin = new CWnd();
	  if(!aWin){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
	  }
	  if(!aWin->Attach(myWin)){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  delete aWin;
		  return;
	  }
    String s;
    s = SSI_EXTRACT(CDataString, 0);
    theAPI.m_ReturnStatus = TypeKeys2(aWin, s, 1);
	  aWin->Detach();
	  delete aWin;
    return;
	}else if(theAPI.m_FunctionName == "KeyUp"){
	  CWnd* aWin = new CWnd();
	  if(!aWin){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  return;
	  }
	  if(!aWin->Attach(myWin)){
		  theAPI.m_ReturnStatus = STAT_ERR;  // Internal Error
		  delete aWin;
		  return;
	  }
    String s;
    s = SSI_EXTRACT(CDataString, 0);
    theAPI.m_ReturnStatus = TypeKeys2(aWin, s, 2);
	  aWin->Detach();
	  delete aWin;
    return;
  }

	if(Val && hMenu){
		CMenu Menu;
		if(!Menu.Attach(hMenu)){
			P_MAKEERR2(ERR_P00200, WinName.Str(), iWinTag);   // Invalid Menu
			return;
		}

		// This is menu stuff
		if(theAPI.m_FunctionName == "Select"){
			theAPI.m_ReturnStatus = PostMessage(WM_COMMAND, (WPARAM)Val, 0);
		}else if(theAPI.m_FunctionName == "IsChecked"){
			CDataBool b;
			if(Menu.GetMenuState(Val, MF_BYCOMMAND) & MF_CHECKED){
				b.Data = 1;
			}
			theAPI.m_ReturnStatus = theAPI.SetReturnData(&b);
		}else if(theAPI.m_FunctionName == "IsEnabled"){
			CDataBool b;
			if((Menu.GetMenuState(Val, MF_BYCOMMAND) & MF_GRAYED) || (Menu.GetMenuState(Val, MF_BYCOMMAND) & MF_DISABLED)){
				b.Data = 0;
			}else{
				b.Data = 1;
			}
			theAPI.m_ReturnStatus = theAPI.SetReturnData(&b);
    }else if(theAPI.m_FunctionName == "IsSeparator"){
			CDataBool b;

      //UINT i = Menu.GetMenuState(Val, MF_BYCOMMAND);
			//if(i & MF_SEPARATOR){

      if(Menu.GetMenuState(Val, MF_BYCOMMAND) & MF_SEPARATOR){
				b.Data = 1;
			}else{
				b.Data = 0;
			}
			theAPI.m_ReturnStatus = theAPI.SetReturnData(&b);
    }else if(theAPI.m_FunctionName == "GetMenuText"){
			CDataString s;
      CString cs;
      Menu.GetMenuString(Val, cs, MF_BYCOMMAND);
      s.Data = cs.GetString();
			theAPI.m_ReturnStatus = theAPI.SetReturnData(&s);
    }else if(theAPI.m_FunctionName == "GetMenuCount"){
			CDataInt i;
      i.Data = Menu.GetMenuItemCount();
			theAPI.m_ReturnStatus = theAPI.SetReturnData(&i);
		}else{
			P_MAKEERR1(ERR_P00201, theAPI.m_FunctionName.Str());    // Function not supported by Menu
		}
		Menu.Detach();
		return;
	}

	// Check if it is a partial class here... so can send *correct* class to MINION
	//  Since now we are sending classes to MINION (MINION used to find it), we dont
	//  want to accidentally send one with a '*' in it...
  // Note that this is *after* defines
	if(LocClass.Find("*") >= 0){
		LocClass = GetClass(myWin);
	}


  // Dont want to use Minion for many classes... will take too much time
  if(IsLocalClass(LocClass)){
    CFunctionProcessor aProc;
	String ExtraData = "";
    aProc.FunctionProcessor(theAPI, myWin, LocClass, ExtraData); 
    return;
  }



	// Sync local data types
	LocalAddMap(CDataInt::GetRegisteredType(), CDataInt::GetRegisteredType());
	LocalAddMap(CDataBool::GetRegisteredType(), CDataBool::GetRegisteredType());
	LocalAddMap(CDataString::GetRegisteredType(), CDataString::GetRegisteredType());
	LocalAddMap(CDataReal::GetRegisteredType(), CDataReal::GetRegisteredType());
	LocalAddMap(CDataVoid::GetRegisteredType(), CDataVoid::GetRegisteredType());


	// Regular (MINION) mode
	if(1){
		// Get the process ID
		DWORD tID = GetWindowThreadProcessId(myWin, SSI_NULL);
		// Set the Minion Hook
		HWND hMinion = SetMinionHook(tID, 1);

		// Get the memor map pointer
		aptr = (char*)aMap.MakePointer();

		// If Minion never hooked, return error
    // hMinion is no longer a window handle
		if(!hMinion){
			P_MAKEERR0(ERR_P00300);
			// "Phantom Internal Error: Minion not created"
			return;
		}

    // hMinion is no longer a window handle
    //tID = GetWindowThreadProcessId(hMinion, SSI_NULL);

		CDataString ClassData;
		CDataString ExtraData;
		ClassData.Data = LocClass;
		SSI_INT64 BytesWrote = WriteDataObject(aptr, &ClassData);
		BytesWrote = BytesWrote + WriteDataObject(aptr+BytesWrote, &ExtraData);
		WriteFunctionAPI(aptr+BytesWrote, theAPI);

		ClearMinionSync();
		MinionLog("--- Sending Tags...");

		// Sync the data types
    if(USE_MINION_WIN){
		//Deprecated...
		  SendMessage(hMinion, WM_COMMAND, MINION_SETVOIDTYPE, (LPARAM)CDataVoid::GetRegisteredType());
		  SendMessage(hMinion, WM_COMMAND, MINION_SETINTTYPE, (LPARAM)CDataInt::GetRegisteredType());
		  SendMessage(hMinion, WM_COMMAND, MINION_SETSTRINGTYPE, (LPARAM)CDataString::GetRegisteredType());
		  SendMessage(hMinion, WM_COMMAND, MINION_SETBOOLTYPE, (LPARAM)CDataBool::GetRegisteredType());
		  SendMessage(hMinion, WM_COMMAND, MINION_SETREALTYPE, (LPARAM)CDataReal::GetRegisteredType());
    }else{
      PostThreadMessage(tID, WM_COMMAND, MINION_SETINTTYPE, (LPARAM)CDataInt::GetRegisteredType());
		  PostThreadMessage(tID, WM_COMMAND, MINION_SETSTRINGTYPE, (LPARAM)CDataString::GetRegisteredType());
		  PostThreadMessage(tID, WM_COMMAND, MINION_SETBOOLTYPE, (LPARAM)CDataBool::GetRegisteredType());
		  PostThreadMessage(tID, WM_COMMAND, MINION_SETREALTYPE, (LPARAM)CDataReal::GetRegisteredType());
		  PostThreadMessage(tID, WM_COMMAND, MINION_SETVOIDTYPE, (LPARAM)CDataVoid::GetRegisteredType());  /// MUST BE LAST
		  PostThreadMessage(tID, WM_COMMAND, MINION_DOFUNCTION, (LPARAM)myWin);
    }

		// Create a new API to read from the pointer
		MINION_FunctionAPI newAPI;

		if(!WaitForSync(1000)){
			P_MAKEERR0(ERR_P00301);  // Internal Error
			MinionLog("No Sync Flag");
		}else{
			MinionLog("Attempting Read");
			// Read the new API
			ReadFunctionAPI(aptr, newAPI);

			// Set the return status and returned data
			theAPI.m_ReturnStatus = newAPI.m_ReturnStatus;
			theAPI.SetReturnData(newAPI.GetReturnData());
		}

		ClearMinionSync(); //== Removed to test Word problem
                       // Re-added on 8/17/08 because I think I forgot about it...
		// Unmap the pointer
		aMap.UnMap(aptr);

		// Remove the hook
		SetMinionHook(tID, 0);

	}else{

		/////////////////////
		//DWORD tID = GetWindowThreadProcessId(hWin, SSI_NULL);
		//HWND hMinion = SetMinionHook(tID);
		//if(!hMinion){
		//	MinionLog("No good hook");
		//}

		aptr = (char*)aMap.MakePointer();

		CDataString ClassData;
		CDataString ExtraData;
		ClassData.Data = LocClass;
		SSI_INT64 BytesWrote = WriteDataObject(aptr, &ClassData);
		BytesWrote = BytesWrote + WriteDataObject(aptr+BytesWrote, &ExtraData);
		WriteFunctionAPI(aptr+BytesWrote, theAPI);
		aMap.UnMap(aptr);

    //Sleep(100);
		printf("Phantom Test Mode\n");  // KEEP PRINT
		Internal_FunctionProcessor(theAPI, myWin, LocClass);

		MINION_FunctionAPI newAPI;
		aptr = (char*)aMap.GetPointer();

		CDataString* aData;
		SSI_INT64 BytesRead = 0;

		aData = (CDataString*)ReadDataObject(aptr, BytesRead);
    delete aData;

		ReadFunctionAPI(aptr+BytesRead, newAPI);

		aMap.UnMap(aptr);

		//SetMinionHook(0);
		/////////////////////
	}
}

void CDataWindow::Internal_FunctionProcessor(SSI_FunctionAPI& theAPI, HWND hWin, String& Class)
{
	CFunctionProcessor aProc;
	String ExtraData = "";
	aProc.FunctionProcessor(theAPI, hWin, Class, ExtraData);
}


CStatus CDataWindow::SSI_UpdateVariable(CVariable& aVar, SSI_BOOL bGet)
{
	CDataString aStr;

	VarItor Itor = find(LocVarSet.begin(), LocVarSet.end(), aVar);
	if(Itor != LocVarSet.end()){

	//VarNode* aNode;
	//if(aNode = LocVarSet.find(aVar)){
		if(bGet){
			aVar = *Itor;
			//aNode->Get(aVar);
		}else{
			*Itor = aVar;
			//aNode->Set(aVar);
		}
		return STAT_OK;
	}

	if(aVar.Name == "Tag"){
		if(bGet){
			aStr.Data = WinTag;
			return aVar.SetData((CData*)&aStr);
		}else{
			WinTag = ((CDataString&)aVar.GetWorkingData()).Data;
			return STAT_OK;
		}
	}else	if(aVar.Name == "Class"){
		if(bGet){
			aStr.Data = WinClass;
			return aVar.SetData((CData*)&aStr);
		}else{
			WinClass = ((CDataString&)aVar.GetWorkingData()).Data;
			return STAT_OK;
		}
	}
	MAKEERR2(ERR_P00101, aVar.Name.Str(), WinClass.Str());
}

SSI_INT64 CDataWindow::GetRegisteredType(void)
{
	return sType;
}

CStatus CDataWindow::AddLocalVariable(CData* InData, String& Name)
{
	if(!InData) return STAT_ERR;  // Internal Error
	
	CVariable aVar;
	aVar.Name = Name;
	
	aVar.SetType(InData->Type);

	String RetMess;
	CStatus RetStat;
	VarItor Itor = find(LocVarSet.begin(), LocVarSet.end(), aVar);
	if(Itor != LocVarSet.end())
  {
		aVar = *Itor;
		DimNode Dims = aVar.GetDims();
		DimNode NewDim = new_array_node();
		if(Dims){
			NewDim->Dim = Dims->Dim+1;
		}else{
			NewDim->Dim = 0;
		}
		aVar.SetData(InData, NewDim);
    del_array_node(NewDim);
		*Itor = aVar;
	}else{
		aVar.SetData(InData);
		LocVarSet.push_back(aVar);
	}
  return STAT_SUCCESS;
}

void CDataWindow::ListToScreen(CEngine* anEng, SSI_INT64 InLevel)
{
	String Line;

	int ctr;
	for(ctr = 0; ctr < InLevel; ctr++){
		Line = Line + "   ";
	}

	Line = Line + WinName;
	Line = Line + " {Class:";
	Line = Line + WinClass;
	Line = Line + "; Tag:";
	if(iWinTag || (WinClass == "MenuItem" || WinClass == "Menu")){
		String s;
		s.Format("[%d]", iWinTag);
		Line = Line + s;
	}else{
		Line = Line + WinTag;
	}
	
	Line = Line + "}";
	anEng->GetOutStream()->Disp(Line, 1);

	VarItor Children = LocVarSet.begin();
	while(Children != LocVarSet.end()){
		CVariable Child;
		Child = *Children;
		CDataWindow* aWin = (CDataWindow*)(&Child.GetWorkingData());
		aWin->ListToScreen(anEng, InLevel+1);
		++Children;
	}
}

bool CDataWindow::ConstructChildPath(CDataWindow* Child)
{
	DataNode aNode = CopyPath(Path);
	DataNode top = aNode;
	if(!aNode){
		aNode = GetFreshNode(aNode);
		top = aNode;
	}else{
		while(aNode->FChild){
			aNode = aNode->FChild;
		}
		aNode->FChild = GetFreshNode(aNode->FChild);
		aNode = aNode->FChild;
		if(!aNode){
			return false;
		}
	}

	*aNode->WinName = WinName;
	*aNode->WinClass = WinClass;
	*aNode->WinTag = WinTag;
	aNode->iWinTag = iWinTag;

	if(Child->Path){
		DelDataNodeTree(Child->Path);
	}

	Child->Path = top;
	return true;
}

String CDataWindow::GetPathString(){
	String Ret;
	DataNode node = Path;
	while(node){
		Ret = Ret + *node->WinName + ".";
		node = node->FChild;
	}
	Ret = Ret + WinName;
	return Ret;
}

CStatus CDataWindow::SetDelay(int newDelay)
{
	if(newDelay < 0) newDelay = 0;
	iDelay = newDelay;
	return STAT_OK;
}

HWND CDataWindow::FindMenu(HWND Par, DataNode CurrNode, UINT& Val, HMENU& hMenu)
{
	Val = 0;
	if(!Par) return 0;
	//if(!CurrNode) return 0; Dont need this... and prevents top-levels from succeeding
	
	CMenu* Menu;
	int Num;
	CWnd* Win = new CWnd();
	
	Win->Attach(Par);
	Menu = Win->GetMenu();
	Win->Detach();
	delete Win;
	if(Menu == SSI_NULL){
		return 0;
	//Error.Format(ERR00034, (LPCTSTR)Command);
	//LogError(Error);
	//return FALSE;
	//	return STAT_ERR;
	}
	while(CurrNode){
		Num = CurrNode->iWinTag;
		if(!(*CurrNode->WinClass == "MenuItem")){
			if(!(*CurrNode->WinClass == "Menu")){
				return 0;
			}
		}

		//if(!CurrNode->Next) break;
		Menu = Menu->GetSubMenu(Num); 
		if(!Menu){
			return 0;
		}
		CurrNode = CurrNode->Next;
	}
	
	hMenu = Menu->m_hMenu;
	Val = Menu->GetMenuItemID(iWinTag);

		//if(Data->WinTag->GetLength() > 0){
		//		Num = StrToInt(*Data->WinTag);
		//		Menu = Menu->GetSubMenu(Num); 
		//		if(Menu == SSI_NULL){
					//Error.Format(ERR00035, (LPCTSTR)Command, Num);
					//LogError(Error);
					//return FALSE;
		//			return STAT_ERR;
		//		}
		//		if(!Data->FChild) break;
		//	}
			//Data = Data->FChild;
			//Class = *Data->WinClass;
			//pStripQuotes(&Class);
			//if(Class == "MenuItem") break;
	//Menu->
	return Par; //Menu->GetMenuItemID(Num);
}

CStatus CDataWindow::PostMessage(UINT Cmd, WPARAM wParam, LPARAM lParam)
{
	CWnd aWin;
	aWin.Attach(myWin);
	if(aWin.PostMessage(Cmd, wParam, lParam)){
		aWin.Detach();
		return STAT_OK;
	}else{
		aWin.Detach();
		MAKEERR0(ERR_P00400);
	}
}

CStatus CDataWindow::CaptureBitmap(CDataBitmap& Ret)
{
	CWnd* aWnd = new CWnd;
	if(!aWnd){
		MAKEERR0(ERR_P00410);
	}
	if(!aWnd->Attach(myWin)){
		delete aWnd;
		MAKEERR0(ERR_P00411);
	}

	CDC* aDC = SSI_NULL;
  RECT aRect;

	CBitmap bmp;

	char flg = 0;
	CPalette  pal;

	aDC = aWnd->GetDC();
	
	aWnd->GetClientRect(&aRect);
	aWnd->Detach();

	delete aWnd;
	aWnd = 0;

	if(!aDC){
		//return STAT_ERR;
    MAKEERR0(ERR_P00418);
	}

	CRect Rect = aRect;
	CSize aSize;
	aSize.SetSize(Rect.Width(), Rect.Height());
	if(!WndToBmp(aDC, aSize, Ret)){
		//return STAT_ERR;
    MAKEERR0(ERR_P00419);
	}else{
		return STAT_OK;
	}
}

	////////////////////////////////////////////////////////////
char* CDataWindow::DDBToDIB(CBitmap &bitmap, DWORD dwCompression, CPalette *pPal, BITMAPINFOHEADER &bi, int &Offset){
  
	char* BitData = 0;
	
	BITMAP bm;
  DWORD dwLen;
  HDC hDC;
  HPALETTE hPal;
  ASSERT(bitmap.GetSafeHandle() );

  // The function has no arg for bitfields
  if(dwCompression == BI_BITFIELDS ) return SSI_NULL;

  // If a palette has not been supplied use defaul palette
  hPal = (HPALETTE) pPal->GetSafeHandle();
  if(hPal==SSI_NULL) hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

  // Get bitmap information
  bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

	WORD cClrBits = (WORD)(bm.bmPlanes * bm.bmBitsPixel); 
	if ( cClrBits == 1) cClrBits = 1;
	else if (cClrBits <= 4) cClrBits = 4;
	else if (cClrBits <= 8) cClrBits = 8;
	else if (cClrBits <= 16) cClrBits = 16;
	else if (cClrBits <= 24) cClrBits = 24;

  //Initialize the bitmapinfoheader
  bi.biSize = sizeof(BITMAPINFOHEADER);
  bi.biWidth = bm.bmWidth;
  bi.biHeight = bm.bmHeight;
  bi.biPlanes = 1;
  bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel; 
  bi.biCompression = dwCompression;
  bi.biSizeImage = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrImportant = 0;

	if (cClrBits < 24) bi.biClrUsed = (1<<cClrBits);
  // Compute the size of the  infoheader and the color table
  int nColors = (1 << bi.biBitCount);
  if (nColors > 256 ) nColors= 0;
  dwLen = bi.biSize + nColors * sizeof(RGBQUAD);
	Offset = nColors * sizeof(RGBQUAD);

  // We need a device context to get the DIB from
  hDC = ::GetDC(SSI_NULL);
  hPal = SelectPalette(hDC,hPal,FALSE);
  RealizePalette(hDC);

  // Call GetDIBits with a SSI_NULL lpBits param, so the device driver 
  // will calculate the biSizeImage field 
  GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight, (LPBYTE)SSI_NULL, (LPBITMAPINFO)&bi, (DWORD)DIB_RGB_COLORS);

	// If the driver did not fill in the biSizeImage field, then compute it
  // Each scan line of the image is aligned on a DWORD (32bit) boundary
  if(bi.biSizeImage == 0){
		bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

    // If a compression scheme is used the result may infact be larger
    // Increase the size to account for this.
    if(dwCompression != BI_RGB) bi.biSizeImage = (bi.biSizeImage * 3) / 2;
  }

  // Realloc the buffer so that it can hold all the bits
	
	BitData = new char[bi.biSizeImage];
	BOOL bGotBits = GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight, (LPBYTE)BitData, (LPBITMAPINFO)&bi, (DWORD)DIB_RGB_COLORS);
	
	//Start scan line
  //# of scan lines
  // address for bitmap bits
  // address of bitmapinfo
  // Use RGB for color table

  if(!bGotBits ){
    SelectPalette(hDC,hPal, FALSE);
    ::ReleaseDC(SSI_NULL,hDC);
		delete [] BitData;
    return 0;
  }

  SelectPalette(hDC,hPal, FALSE);
  ::ReleaseDC(SSI_NULL,hDC);

	return BitData;
}

BOOL CDataWindow::WndToBmp(CDC *pDC, CSize cbImage, CDataBitmap& Ret)
{
//it will capture wnd and save into bmp file
  CBitmap bmp, *pOldBmp;
  CRect rect;
  CPalette pal;
  LOGPALETTE *pLp;

  if(pDC == SSI_NULL){
     //AfxMessageBox("DC Not Found");
     return FALSE;
  }

	CDC memdc;
        
	
  memdc.CreateCompatibleDC(pDC);
  bmp.CreateCompatibleBitmap(pDC,cbImage.cx, cbImage.cy);
  pOldBmp = memdc.SelectObject(&bmp);
  memdc.BitBlt(0, 0, cbImage.cx, cbImage.cy, pDC, 0, 0, SRCCOPY);
  CDC dcdc;
	dcdc.CreateCompatibleDC(SSI_NULL);
  dcdc.BitBlt(0, 0, cbImage.cx, cbImage.cy, pDC, 0, 0, SRCCOPY);
  if(pDC->GetDeviceCaps(RASTERCAPS)& RC_PALETTE){
		int nSize;
    nSize = sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256;
    pLp = (LOGPALETTE*) new BYTE[nSize];
    pLp->palVersion = 0x300;
    pLp->palNumEntries = 256;
    GetSystemPaletteEntries(pDC->m_hDC, 0, 256, pLp->palPalEntry);
    pal.CreatePalette(pLp);
    delete [] pLp;
  }
        
  memdc.SelectObject(pOldBmp);
	int Offset;

	char* BitData;
	BITMAPINFOHEADER bi;

	BitData = DDBToDIB(bmp, BI_RGB, &pal, bi, Offset);
	if(BitData == SSI_NULL) return FALSE;
//*************************************

	BITMAPFILEHEADER hdr;

  int nColors = 1 << bi.biBitCount;
        
  hdr.bfType = ((WORD) ('M' << 8) | 'B');
	hdr.bfSize = DWORD(bi.biSizeImage) + sizeof(hdr);
  hdr.bfReserved1 = 0;
  hdr.bfReserved2 = 0;
	hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER)) + bi.biSize;
 
	BMP_FILE_HDR aFile;
	BMP_INFO_HDR aInfo;
	aInfo.biBitCount = bi.biBitCount;
	aInfo.biClrImportant = bi.biClrImportant;
	aInfo.biClrUsed = bi.biClrUsed;
	aInfo.biCompression = bi.biCompression;
	aInfo.biHeight = bi.biHeight;
	aInfo.biPlanes = bi.biPlanes;
	aInfo.biSize = bi.biSize;
	aInfo.biSizeImage = bi.biSizeImage;
	aInfo.biWidth = bi.biWidth;
	aInfo.biXPelsPerMeter = bi.biXPelsPerMeter;
	aInfo.biYPelsPerMeter = bi.biYPelsPerMeter;

	aFile.bfOffBits = hdr.bfOffBits;
	aFile.bfReserved1 = hdr.bfReserved1;
	aFile.bfReserved2 = hdr.bfReserved2;
	aFile.bfSize = hdr.bfSize;
	aFile.bfType = hdr.bfType;

	Ret.SetBitmap(aFile, aInfo, BitData, aInfo.biSizeImage);

//	m_file.Write(&hdr,sizeof(hdr));
//	m_file.Write(&bi,sizeof(bi));
//	m_file.Write(BitData,bi.biSizeImage);
//  m_file.Close();
	delete [] BitData;
  return 1;
}





/*

	CStatus RetStat;
	CWnd* aWnd = new CWnd();
	if(!aWnd){
		MAKEERR0(ERR_P00410);
	}
	if(!aWnd->Attach(myWin)){
		delete aWnd;
		MAKEERR0(ERR_P00411);
	}

	CDC* aDC = SSI_NULL;
  RECT Rect;
	RECT aRect;

  int i = 0;
  int j = 0;
  int NumPix = 0;

  BYTE red_byte = 0;
  BYTE green_byte = 0;
  BYTE blue_byte = 0;
  int red_int = 0;
  int green_int = 0;
  int blue_int = 0;

  COLORREF CurrColor = 0;
  CString Data = "";
  CString sPixel = "";

  aDC = aWnd->GetDC();
	aWnd->GetClientRect(&aRect);

  //if(!aWnd->GetParent()){
  //  aWnd->ClientToScreen(&aRect);
  //}

  if(!aDC){
		aWnd->Detach();
		delete aWnd;
    MAKEERR0(ERR_P00412);
  }

  CRgn aRgn;
	if(!aRgn.CreateRectRgnIndirect(&aRect)){
		aWnd->Detach();
		delete aWnd;
    MAKEERR0(ERR_P00413);
	}

  if(aDC->SelectClipRgn(&aRgn) != SIMPLEREGION){
		aWnd->Detach();
		delete aWnd;
    MAKEERR0(ERR_P00414);
  }

  Rect.bottom = aRect.bottom;
  Rect.left = aRect.left;
  Rect.right = aRect.right;
  Rect.top = aRect.top;

  int iH = Rect.bottom - Rect.top;
  int iW = Rect.right - Rect.left;

  CBitmap* aBMP = aDC->GetCurrentBitmap();
  if(!aBMP){
		aWnd->Detach();
		delete aWnd;
		MAKEERR0(ERR_P00415);
	}

  BITMAP pBITMAP;
  aBMP->GetBitmap(&pBITMAP);

  int bpp = 8;
  int ExtraZeros = 4-((iW * bpp / 8) % 4);
  if(ExtraZeros == 4) ExtraZeros = 0;
  int num_bytes = (iW * iH * bpp / 8) + ExtraZeros * iH;

  BITMAPINFOHEADER aInfo;
  aInfo.biBitCount = bpp;
  aInfo.biClrUsed = 0;
  aInfo.biClrImportant = 0;
  aInfo.biCompression = BI_RGB;
  aInfo.biWidth = iW;
  aInfo.biHeight = iH;
  aInfo.biPlanes = 1;
  aInfo.biSizeImage = num_bytes;
  aInfo.biXPelsPerMeter = 0;
  aInfo.biYPelsPerMeter = 0;
  aInfo.biSize = sizeof(BITMAPINFOHEADER);

  BYTE* ByteData = new BYTE[num_bytes];

  BITMAPFILEHEADER aFile;
  aFile.bfType = 'MB';
  aFile.bfReserved1 = 0;
  aFile.bfReserved2 = 0;
  aFile.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
  aFile.bfSize = num_bytes;
  
  int ctr = 0;
  int ctr2 = 0;

  int wStart = Rect.right - 1;
  int wStop = Rect.right - iW;
  int hStart = Rect.top;
  int hStop = Rect.top + iH;

  for(i=hStart; i < hStop; i++)
  {
    for(ctr2 = 0; ctr2 < ExtraZeros; ctr2++)
    {
      ByteData[ctr++] = 0;
      NumPix++;
    }
    for(j=wStart; j >= wStop; j--)
    {
      CurrColor = aDC->GetPixel(j, i);

			int qq = (int)CurrColor;
			if(qq == -1){
				aWnd->Detach();
				delete aWnd;
				MAKEERR0(ERR_P00416);
			}

      red_int = CurrColor & 0x000000FF;
      red_byte = (BYTE)red_int;
      green_int = CurrColor & 0x0000FF00;
      green_byte = green_int >> 8;
      blue_int = CurrColor & 0x00FF0000;
      blue_byte = blue_int >> 16;

			//red_byte = 200;
			//green_byte = 0;
			//blue_byte = 0;

      ByteData[ctr++]=blue_byte;
      NumPix++;
      ByteData[ctr++]=green_byte;
      NumPix++;
      ByteData[ctr++]=red_byte;
      NumPix++;
    }
  }

	aWnd->Detach();
	delete aWnd;

	if(!Ret.SetBitmap(ByteData, num_bytes, iW, iH, bpp)){
		MAKEERR0(ERR_P00417);
	}
	delete ByteData;

	*/
//	return STAT_OK;

//}

CStatus CDataWindow::AddFunction(CFunctionDecl& NewFunc, String& CurrClass)
{
	SSI_FunctionAPI anAPI;
	anAPI.m_FunctionName = NewFunc.Name;
	SSI_INT64 Count = NewFunc.getNumParams();
	SSI_INT64 ctr = 0;
	CVariable aVar;
	
	if(!anAPI.InitParams(Count)){
		return STAT_ERR;  // Internal error
	}
	
	
	for(ctr = 0; ctr < Count; ctr++){
		aVar.SetType(NewFunc.getParamType(ctr));
		anAPI.AddParameter(aVar, ctr);
	}
	if(!Phantom_RegisterFunction(anAPI, CurrClass)){
		return STAT_OK;  // Function already registered, just need to add class
	}
	
	return CData::AddFunction(NewFunc);
	
	//return STAT_OK;
}

String CDataWindow::GetClass(HWND hWin)
{
	String Ret;
	char sTemp[1024];
	GetClassName(hWin, sTemp, 1024);
	Ret = sTemp;
	return Ret;
}

SSI_INT64 CDataWindow::Register(SSI_INT64 NewType){
	sType = NewType;
	return 1;
}

void CDataWindow::UnRegister(){
	sType = 0;
}

CStatus CDataWindow::MouseClick(CWnd* aWnd, int iButton, int X, int Y, int iType)
{
	CStatus RetStat;
	POINT Pt;

	Pt.x = X;
	Pt.y = Y;
	
	aWnd->ClientToScreen(&Pt);

	int sV = GetSystemMetrics(SM_CYSCREEN);
	int sH = GetSystemMetrics(SM_CXSCREEN);

	Pt.x = int(double(double(Pt.x) / double(sH)) * (double)65535);
	Pt.y = int(double(double(Pt.y) / double(sV)) * (double)65535);

	if((iType < PM_CLICK) || (iType > PM_DBLCLICK))
	{
		RetStat.Format(sERROR, "MouseClick parameter 4 must be 0,1,2, or 3");
		return RetStat;
	}

	if(aWnd->GetStyle() & WS_POPUP)
	{
	}
	else if(iType == PM_DOWN)	// Do not want to activate if UP
	{	
		CWnd* TopWin = aWnd->GetTopLevelOwner();
		if(TopWin == SSI_NULL)
		{
			TopWin = aWnd;
		}
		HWND hWnd = TopWin->m_hWnd;
		HWND Fore = GetForegroundWindow();
		if(GetWindowThreadProcessId(hWnd, SSI_NULL) != GetWindowThreadProcessId(Fore, SSI_NULL))
		{
			SetForegroundWindow(hWnd);
			BringWindowToTop(hWnd);
			SetActiveWindow(hWnd);
			SetFocus(hWnd);			
		}		
	}

	DWORD FLAG = MOUSEEVENTF_ABSOLUTE;
	FLAG = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
	mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		

	FLAG = MOUSEEVENTF_ABSOLUTE;	
	
	if(iButton == PM_LEFT)
	{
		if(iType == PM_CLICK)
		{
			FLAG = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_DOWN)
		{
			FLAG |= MOUSEEVENTF_LEFTDOWN;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_UP)
		{
			FLAG |= MOUSEEVENTF_LEFTUP;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_DBLCLICK)
		{
			FLAG = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			
			FLAG = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
	}
	else if(iButton == PM_RIGHT)
	{
		if(iType == PM_CLICK)
		{
			FLAG = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);
		}
		else if(iType == PM_DOWN)
		{
			FLAG |= MOUSEEVENTF_RIGHTDOWN;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_UP)
		{
			FLAG |= MOUSEEVENTF_RIGHTUP;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_DBLCLICK)
		{
			FLAG = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);
			
			FLAG = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);
		}
	}
	else if(iButton == PM_MID)
	{
		if(iType == PM_CLICK)
		{
			FLAG = MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_MIDDLEUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);
		}
		else if(iType == PM_DOWN)
		{
			FLAG |= MOUSEEVENTF_MIDDLEDOWN;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_UP)
		{
			FLAG |= MOUSEEVENTF_MIDDLEUP;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
		}
		else if(iType == PM_DBLCLICK)
		{
			FLAG = MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_MIDDLEUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);

			FLAG = MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_ABSOLUTE;;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);		
			FLAG = MOUSEEVENTF_MIDDLEUP | MOUSEEVENTF_ABSOLUTE;
			mouse_event(FLAG, Pt.x, Pt.y, SSI_NULL, SSI_NULL);
		}
	}else{
		RetStat.Format(sERROR, "MouseClick parameter 1 must be 0,1, or 2");
		return RetStat;
	}
	return STAT_OK;
}

CStatus CDataWindow::TypeKeys(CWnd* aWnd, String& inKeys)
{
	CString Line = inKeys.Str();
	CString Spec;
	int Pos;
	UINT Code;
	UINT KUP = 1073741824;
	UINT KDOWN = 0;
	char lcar = '<';
	char rcar = '>';
	char c;

	// To Activate the Window
	if(aWnd != SSI_NULL)
	{
		CWnd* TopWin = aWnd->GetTopLevelOwner();
		if(TopWin == SSI_NULL)
		{
			TopWin = aWnd;
		}
		HWND hWnd = TopWin->m_hWnd;
		HWND Fore = GetForegroundWindow();
		if(GetWindowThreadProcessId(hWnd, SSI_NULL) != GetWindowThreadProcessId(Fore, SSI_NULL))
		{
			SetForegroundWindow(hWnd);
			BringWindowToTop(hWnd);
			SetActiveWindow(hWnd);
			SetFocus(hWnd);			
		}
	}

	while(Line.GetLength() > 0)
	{
		if(Line.GetAt(0) == lcar)
		{
			if((Pos = Line.Find(rcar)) >= 0)
			{
				Spec = Line.Left(Pos);
				Spec = Spec.Right(Spec.GetLength() - 1);
				TypeKeysEx(String((LPCTSTR)Spec));
				Line = Line.Right(Line.GetLength() - Pos - 1);
			}
		}
		else
		{
			c = Line.GetAt(0);
			Code = (UINT)c;
			Code = VkKeyScan(Code);
			Line = Line.Right(Line.GetLength() - 1);
			if(IsShifted(c))
			{
				SendKey(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), SSI_NULL, SSI_NULL);
			}
			SendKey(Code, MapVirtualKey(Code, 0), SSI_NULL, SSI_NULL);
			SendKey(Code, MapVirtualKey(Code, 0), KEYEVENTF_KEYUP, SSI_NULL);
			if(IsShifted(c))
			{
				SendKey(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_KEYUP, SSI_NULL);
			}
		}
	}	
	return STAT_OK;
}

CStatus CDataWindow::TypeKeys2(CWnd* aWnd, String &InParams, UINT Type)
{
	CString Line = InParams.Str();
	CString Spec;
	int Pos;
	UINT Code;
	UINT KUP = 1073741824;
	UINT KDOWN = 0;
	char lcar = '<';
	char rcar = '>';
	char c;
	BOOL bErr = FALSE;

	if(Line.GetAt(0) == lcar){
		if((Pos = Line.Find(rcar)) >= 0){
			Spec = Line.Left(Pos);
			Spec = Spec.Right(Spec.GetLength() - 1);				
			Code = GetKeyCode(String(Spec.GetString()));
		}
	}else{
		if(Line.GetLength() > 1){
			bErr = TRUE;			
		}
		c = Line.GetAt(0);
		Code = (UINT)c;
		Code = VkKeyScan(Code);
	}	
	if(Type == 1){	
		if(bErr){
			//Error.Format(ERR00111, Line);
			//LogError(Error);
			//return;
			MAKEERR1(ERR_P01600, (LPCTSTR)Line);
		}
    SendKey(Code, MapVirtualKey(Code, 0), 0, 0);
    
		//aWnd->PostMessage(WM_KEYDOWN, Code, 0);
	}else{
		if(bErr){
			//Error.Format(ERR00112, Line);
			//LogError(Error);
			//return;
			MAKEERR1(ERR_P01601, (LPCTSTR)Line);
		}
		//aWnd->PostMessage(WM_KEYUP, Code, 0);
    SendKey(Code, MapVirtualKey(Code, 0), KEYEVENTF_KEYUP, 0);
	}
	return STAT_OK;
}




UINT CDataWindow::GetKeyCode(String& Line)
{
	UINT Ret = 0;
	if(Line == "ESC")
	{
		Ret = VK_ESCAPE;
	}
	else if(Line == "BKSP")
	{
		Ret = VK_BACK;
	}
	else if(Line == "TAB")
	{
		Ret = VK_TAB;
	}
	else if(Line == "ENTER")
	{
		Ret = VK_RETURN;
	}
	else if(Line == "CTRL")
	{
		Ret = VK_CONTROL;
	}
	else if(Line == "SHIFT")
	{
		Ret = VK_SHIFT;
	}
	else if(Line == "PRISC")
	{
		Ret = VK_SNAPSHOT;
	}
	else if(Line == "ALT")
	{
		Ret = VK_MENU;		
	}
	else if(Line == "SPACE")
	{
		Ret = VK_SPACE;
	}
	else if(Line == "CAPS")
	{
		Ret = VK_CAPITAL;
	}
	else if(Line == "F1")
	{
		Ret = VK_F1;
	}
	else if(Line == "F2")
	{
		Ret = VK_F2;
	}
	else if(Line == "F3")
	{
		Ret = VK_F3;
	}
	else if(Line == "F4")
	{
		Ret = VK_F4;
	}
	else if(Line == "F5")
	{
		Ret = VK_F5;
	}
	else if(Line == "F6")
	{
		Ret = VK_F6;
	}
	else if(Line == "F7")
	{
		Ret = VK_F7;
	}
	else if(Line == "F8")
	{
		Ret = VK_F8;
	}
	else if(Line == "F9")
	{
		Ret = VK_F9;
	}
	else if(Line == "F10")
	{
		Ret = VK_F10;
	}
	else if(Line == "F11")
	{
		Ret = VK_F11;
	}
	else if(Line == "F12")
	{
		Ret = VK_F12;
	}
	else if(Line == "NUM")
	{
		Ret = VK_NUMLOCK;
	}
	else if(Line == "SCROLL")
	{
		Ret = VK_SCROLL;
	}
	else if(Line == "HOME")
	{
		Ret = VK_HOME;
	}
	else if(Line == "UP")
	{
		Ret = VK_UP;
	}
	else if(Line == "PGUP")
	{
		Ret = VK_PRIOR;
	}
	else if(Line == "LEFT")
	{
		Ret = VK_LEFT;
	}
	else if(Line == "CENTER")
	{
		Ret = VK_CLEAR;
	}
	else if(Line == "RIGHT")
	{
		Ret = VK_RIGHT;
	}
	else if(Line == "END")
	{
		Ret = VK_END;
	}
	else if(Line == "DOWN")
	{
		Ret = VK_DOWN;
	}
	else if(Line == "PGDN")
	{
		Ret = VK_NEXT;
	}
	else if(Line == "INS")
	{
		Ret = VK_INSERT;
	}
	else if(Line == "DEL")
	{
		Ret = VK_DELETE;
	}
	else if(Line == "LWIN")
	{
		Ret = VK_LWIN;
	}
	else if(Line == "RWIN")
	{
		Ret = VK_RWIN;
	}
	else if(Line == "APPS")
	{
		Ret = VK_APPS;
	}
	else if(Line == "*")
	{
		Ret = VK_MULTIPLY;
	}
	else if(Line == ".")
	{
		Ret = VK_DECIMAL;
	}
	else if(Line == "/")
	{
		Ret = VK_DIVIDE;
	}
	else if(Line == "+")
	{
		Ret = VK_ADD;
	}
	else if(Line == "-")
	{
		Ret = VK_SUBTRACT;
	}
	else if(Line.GetLength() == 1)
	{
		Ret = (UINT)Line[0] ;
		Ret = VkKeyScan(Ret);
	}
	return Ret;
}

CStatus CDataWindow::TypeKeysEx(String& InParams)
{
	char dash = '-';
	int Pos;
	UINT dCode;
	BOOL bDash = FALSE;
	UINT Code;
	UINT KDOWN = 0;
	UINT EXT = 16777216;
	UINT ALT = 536870912;
	UINT KUP = 2147483648;
	UINT FLAG = 0;
	CString Line = InParams.Str();
	CString Key;
	UINT ScanCode = 0;
	UINT dScanCode = 0;

	if((Pos = Line.Find(dash)) >= 0)
	{
		Key = Line.Left(Pos);
		if(Line[Pos+1] == '-')
		{
			bDash = TRUE;
		}
		Line = Line.Right(Line.GetLength() - Pos - 1);

		dCode = GetKeyCode(String("-"));
		dScanCode = MapVirtualKey(dCode, 0);

		Code = GetKeyCode(String(Key));
		if(Code > 0)
		{
			ScanCode = MapVirtualKey(Code, 0);
			if(ScanCode > 0)
			{
				SendKey(Code, ScanCode, SSI_NULL, SSI_NULL);
				if(bDash)
				{
					SendKey(dCode, dScanCode, SSI_NULL, SSI_NULL);
					Line = Line.Right(Line.GetLength() - 1);
				}
				TypeKeysEx(String((LPCTSTR)Line));
				if(bDash)
				{
					SendKey(dCode, dScanCode, KEYEVENTF_KEYUP, SSI_NULL);
					Line = Line.Right(Line.GetLength() - 1);
				}
				SendKey(Code, ScanCode, KEYEVENTF_KEYUP, SSI_NULL);
			}
		}else{
			MAKEERR1(ERR_P01602, (LPCTSTR)Line);
		}
	}
	else
	{
		Code = GetKeyCode(String((LPCTSTR)Line));
		if(Code > 0)
		{
			ScanCode = MapVirtualKey(Code, 0);
			//if(ScanCode > 0)
			//{
				SendKey(Code, ScanCode, 0, SSI_NULL);
				SendKey(Code, ScanCode, KEYEVENTF_KEYUP, SSI_NULL);
			//}
		}else{
			MAKEERR1(ERR_P01603, (LPCTSTR)Line);
		}
	}
	return STAT_OK;	
}

void CDataWindow::SendKey(UINT Code, UINT ScanCode, DWORD Flag1, DWORD Flag2){
  //INPUT I;
  //I.type = INPUT_KEYBOARD;
  //I.ki.wScan = Code;
  //I.ki.wVk = ScanCode;
  //I.ki.dwFlags = Flag1;
  //I.ki.dwExtraInfo = Flag2;
  //SendInput(1, &I, sizeof(I));

  keybd_event(Code, ScanCode, Flag1 | KEYEVENTF_EXTENDEDKEY, SSI_NULL);
}


int CDataWindow::IsShifted(char c)
{
	CString ShiftList = "~!@#$%^&*()_+?<>:\"{}|";
	if(ShiftList.Find(c) >= 0) return 1;
	if(isupper((int)c)) return 1;
	return 0;

}

//DataNode CDataWindow::InitializePath(void){
//	Path = GetFreshNode(Path);
//  Path->iWinTag = iWinTag;
//  *(Path->WinTag) = WinTag;
//  *(Path->WinType) = WinType;
//  *(Path->WinName) = WinName;
//  *(Path->WinClass) = WinClass;
//	return Path;
//}


DataNode CDataWindow::CreatePathTree(void)
{
  DataNode Ret = GetFreshNode(0);
  Ret->iWinTag = iWinTag;
  //Ret->IsChild = iChild;
  //Ret->IsChild = iParent;
  *(Ret->WinTag) = WinTag;
  *(Ret->WinType) = WinType;
  *(Ret->WinName) = WinName;
  *(Ret->WinClass) = WinClass;
  
  if(LocVarSet.size() > 0){
    DataNode FChild = 0;
    DataNode pChild = 0;
    DataNode aChild = 0;
	  VarItor Children = LocVarSet.begin();
	  while(Children != LocVarSet.end()){
		  CVariable Child;
		  Child = *Children;
		  CDataWindow* aWin = (CDataWindow*)(&Child.GetWorkingData());	
      aChild = aWin->CreatePathTree();
      aChild->Prev = pChild;
      if(pChild){
        pChild->Next = aChild;
      }
      pChild = aChild;
      if(FChild == 0){
        FChild = aChild; 
      }
		  ++Children;
	  }
    Ret->FChild = FChild;
  }
  return Ret;
}

int CDataWindow::InitializeFromWindow(const CWnd* In)
{
  //iChild = 0;
  //iParent = 0;
  //iLevel = 0;
  iWinTag = 0;
  myWin = 0;
  setWin = 0;
  if(In == NULL){
    WinClass = "";
    WinName = "";
    WinTag = "";
    WinType == "";
  }else if(IsWindow(In->m_hWnd) == FALSE){
    WinClass = "";
    WinName = "";
    WinTag = "";
    WinType == "";
  }else{
    //if(In->GetParent() != NULL){
    //  iChild = 1;
    //}
    //if(In->GetTopWindow() != NULL){
    //  iParent = 1;
    //}
    setWin = In->m_hWnd;
    myWin = setWin;
    WinClass = GetClass(setWin);
    WinType = "MainWin";
    CString S;
    In->GetWindowText(S);
    WinTag = (LPCTSTR)S;
  }
  return 1;
}

SSI_BOOL CDataWindow::boolean()
{
  if(setWin != 0) return 1;
  HMENU H;
  UINT V;
  if(FindMe(V, H)){
    return 1;
  }
  return 0;
}

SSI_BOOL CDataWindow::IsLocalClass(const String& ClassName)
{
  if(ClassName == "SysTreeView32") return 0;
  if(ClassName == "ToolbarWindow32") return 0;
  if(ClassName == "SysTabControl32") return 0;
  if(ClassName == "SysListView32") return 0;

  if(ClassName == "jvm") return 0;

  //if(ClassName == "Internet Explorer_Server") return 0;

  return 1;
}

void CDataWindow::DoDelay(void)
{
	Sleep(iDelay);
}
